using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;

using CommonTypes;
using MVCFramework.Models.Filters;


using System.Reflection;
using MVCFramework.Models.Controllers;

using System.Diagnostics;
using System.Xml;

namespace MVCFramework.Models
{
    [Serializable ]
    public class ModelDecorator : IModel
    {
        #region IView Members
        private MVCFramework.Id<MVCFramework.IModel> _id;
        public MVCFramework.Id<MVCFramework.IModel> Id
        {
            get
            {
                return _id;
            }
            set
            {
                _id = value;
            }
        }

        #endregion

        #region IModel OGL Members  // remove this 

        protected  bool needsUpdate;
        protected  Hashtable _hasTable;

        public Hashtable HashTable
        {
            get
            {
                return _hasTable;
            }
            set
            {
                _hasTable = value;
            }
        }

        public bool NeedsUpdate
        {
            get
            {
                return Model.NeedsUpdate;
            }
            set
            {
                Model .NeedsUpdate = value;
            }
        }

        #endregion

        # region " IEnumerable Implemenation "

        public virtual System.Collections.IEnumerator GetEnumerator()
        {
            return Model.GetEnumerator(); 
        }

        # endregion

        # region Events Decleration "

        [field: NonSerialized]
        public event EventHandler<ModelModificationEventArgs> OnAddElement;
        [field: NonSerialized]
        public event EventHandler<ModelModificationEventArgs> OnRemoveElement;
        [field: NonSerialized]
        public event EventHandler<ModelModificationEventArgs> OnGetElement;

        #endregion

        protected void RaiseAddObjectEvent(IModelData _object)
        {
            if (OnAddElement != null)
                OnAddElement(this, new ModelModificationEventArgs(_object, ModelChangeType.Added));
        }
        protected void RaiseRemoveObjectEvent(IModelData _object)
        {
            if (OnRemoveElement != null)
                OnRemoveElement(this, new ModelModificationEventArgs(_object, ModelChangeType.Removed));
        }

        private IModel _model;

        public IModel Model
        {
            get { return _model ; }
            set { _model = value; }
        }

        public ModelDecorator(IModel model)
        {
            this._model = model;
        }


        # region " Add, Remove , Modify Models Decleration "

        public virtual bool AddObject(IModelData _object)
        {
            needsUpdate = true;
            return Model .AddObject (_object );
        }

        public virtual bool RemoveObject(IModelData _object)
        {
            needsUpdate = true;
            return Model.RemoveObject(_object);
        }

        public virtual object GetObject(int id)
        {
            return Model.GetObject(id);
        }

        public virtual  IList<IModelData> GetGroup(string name)
        {
            return Model.GetGroup(name);
        }

        public virtual IList<IModelData> GetGroup(Type type)
        {
            return Model.GetGroup(type);//TODO : modify this 
        }

        public virtual  bool ContainsGroup(String name)
        {
            return Model.ContainsGroup(name);
        }

        public virtual bool Contains(IModelData _object)
        {
            return Model.Contains(_object);
        }

        public virtual bool Modify(IModelData _object, Vector v)
        {
            return Model.Modify(_object, v);
        }

        # endregion

        # region "IVisitorhost Implementation "

        public void Accept(IVisitor visitor)
        {
           
            visitor.Visit(this);
        }

        # endregion

        #region IModel Members


        public virtual  IList<IModelData> this[string name]
        {
            get { return Model[name]; }
        }
        public virtual IList<IModelData> this[Type type]
        {
            get { return Model[type]; }
        }


        #endregion

        #region IModel Members


        public int MaxId
        {
            get {return Model .MaxId ; }
        }

        #endregion

        #region IModel Members


        public object DeepCopy()
        {
            return Model.DeepCopy();
        }

        #endregion

        #region IModel Members

        public void RequestIdRegistration(object _object)
        {
            Model .RequestIdRegistration (_object );
        }

        #endregion

        #region IModel Members

        public void AttachEventHandlerToData(object _attribute, EventHandler EventHandler)
        {
            Model.AttachEventHandlerToData(_attribute, EventHandler);
        }

        public void DettachEventHandlerToData(object _attribute, EventHandler EventHandler)
        {
            Model.DettachEventHandlerToData(_attribute, EventHandler);
        }

        public T GetObject<T>(object name)
        {
           return  Model.GetObject<T>(name);
        }

        public void SetObject(object name, object _object)
        {
            Model.SetObject(name, _object);
        }

        public object this[object Name]
        {
            get
            {
                return Model[Name];
            }
            set
            {
                Model[Name] = value;
            }
        }

        public void SetObject(object name, object _object, bool addToData)
        {
            Model.SetObject(name, _object, addToData);
        }

        #endregion
    }

    [Serializable]
    public class RecursiveModelDecorator : ModelDecorator
    {
        public RecursiveModelDecorator(IModel model,string id ):base ( model)
        {    this.Id = id;
            DoWireUpDeepAddition();
        }

        protected virtual void DoWireUpDeepAddition()
        {
            this.CheckAdditionRecursive = CheckModelDeepAddition;
            this.CheckRemovalRecursive = CheckModelDeepRemoval;

            RecurseAdditionCallFunction = AddObject;
            RecurseRemovalCallFunction = RemoveObject;
        }

        [NonSerialized]
        protected System.Resources.ResourceManager ModelDataCompositionResources;

        public void SetXmlRecursion(System.Resources.ResourceManager xmlRecource)
        {
            ModelDataCompositionResources = xmlRecource;
            this.CheckAdditionRecursive = CheckXmlDeepAddition ;
            this.CheckRemovalRecursive = CheckXmlDeepRemoval ;

            RecurseAdditionCallFunction = AddObject;
            RecurseRemovalCallFunction = RemoveObject;
        }

        public void SetAttributeRecursion()
        {

        }

        private static readonly LoggerAdapter log = new LoggerAdapter(typeof(IModel));
        public bool ListNotificationIsEnabled = true  ;

        public delegate void GeneralFunction<T>(T _object);
        public delegate bool ActionFunction<T>(T _object);

        private GeneralFunction<object> CheckAdditionRecursive;
        private GeneralFunction<object> CheckRemovalRecursive;

        private ActionFunction<IModelData> RecurseAdditionCallFunction;
        private ActionFunction<IModelData> RecurseRemovalCallFunction;

        public override bool AddObject(IModelData _object)
        {
            CheckModelDeepAddition(_object);

            return Model.AddObject(_object);
        }

        public override bool RemoveObject(IModelData _object)
        {
            CheckModelDeepRemoval(_object);

            return Model.RemoveObject(_object);
        }

        # region "Attribute Configuration for Deep Composition"

        private IDictionary<Type, bool> SimpleCache = new Dictionary<Type, bool>();

        private void CheckModelDeepAddition(object _object)
        {
            //Debug.Assert(_object != null);

            if (_object == null) return;

            if (SimpleCache.ContainsKey(_object.GetType()))
            {
                if (SimpleCache[_object.GetType()] == true)
                    ProccesAdddition(_object);
            }
            else
            {
                # region Check For  Type and add
                if (_object.GetType().IsDefined(typeof(ModelContainmentAttribute), false))
                {
                    object[] atrribute = _object.GetType().GetCustomAttributes(typeof(ModelContainmentAttribute), false);
                    bool inheritance = (atrribute[0] as ModelContainmentAttribute).CheckDeepContainment;
                    IList<IController> _controllersDeactivate = (atrribute[0] as ModelContainmentAttribute)._controllers;

                    SimpleCache.Add(_object.GetType(), inheritance);
                    if (inheritance == true)
                        ProccesAdddition(_object);
                }
                #endregion
            }


        }
        private void ProccesAdddition(object _object)
        {

            PropertyInfo[] properties = _object.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                if (property.IsDefined(typeof(ModelContainmentAttribute), true))
                {
                    log.Info("Propery " + property.ToString() + "Is Examining for Models Addition");
                    MethodInfo getinfo = property.GetGetMethod(true);
                    object[] aa = new object[0];
                    object _returnObject = getinfo.Invoke(_object, aa);
                    if (_returnObject is IList)
                    {
                        log.Info(" List Is Checked for DeepComposition " + _returnObject.ToString());
                        foreach (object data in (_returnObject as IList))
                        {
                            log.Info("data " + data.ToString() + " Is Examining");
                            if (data is IModelData)
                                this.RecurseAdditionCallFunction(data as IModelData);
                        }
                        if (_returnObject is IDomainCollection)
                            RegisterCollectionEventHandler(_returnObject as IDomainCollection);
                    }
                    else if (_returnObject is IModelData)
                        this.RecurseAdditionCallFunction(_returnObject as IModelData);
                    else
                    {
                        log.Info(" Recursive call to DeepAddition  ");
                        CheckModelDeepAddition(_returnObject);
                    }
                }

            }
        }

        private void CheckModelDeepRemoval(object _object)
        {
            // Debug.Assert(_object != null);
            if (_object == null) return;

            if (SimpleCache.ContainsKey(_object.GetType()))
            {
                if (SimpleCache[_object.GetType()] == true)
                    ProccesRemoval(_object);
            }
            else
            {
                # region Check For  Type and add
                if (_object.GetType().IsDefined(typeof(ModelContainmentAttribute), false))
                {
                    object[] atrribute = _object.GetType().GetCustomAttributes(typeof(ModelContainmentAttribute), false);
                    bool inheritance = (atrribute[0] as ModelContainmentAttribute).CheckDeepContainment;

                    SimpleCache.Add(_object.GetType(), inheritance);
                    if (inheritance == true)
                        ProccesRemoval(_object);
                }
                #endregion
                /* * */
            }
        }

        private void ProccesRemoval(object _object)
        {

            foreach (PropertyInfo property in _object.GetType().GetProperties())
            {
                if (property.IsDefined(typeof(ModelContainmentAttribute), true))
                {
                    MethodInfo getinfo = property.GetGetMethod(true);
                    object[] aa = new object[0];
                    object _returnObject = getinfo.Invoke(_object, aa);
                    if (_returnObject is IList)
                    {
                        ListModificationMethod(_returnObject as IList);
                    }
                    else if (_returnObject is IModelData)
                        RecurseRemovalCallFunction(_returnObject as IModelData);
                    else
                    {
                        log.Info("Recursive Call to DeepRemoval");

                        CheckModelDeepRemoval(_returnObject);
                    }
                }

            }
        }

        private void ListModificationMethod(IList list)
        {

            log.Info(" List Is Checked for DeepComposition Removal" + list.ToString());

            if (list is IDomainCollection)
            {
                if (((IDomainCollection)list).IsModelModifiededCollection)
                {
                    IDomainCollection _returnObject = list as IDomainCollection;

                    object _firsObjectInCollection;

                    while ((_returnObject).Count != 0)
                    {
                        _firsObjectInCollection = (_returnObject as IList)[0];

                        log.Info("data " + _firsObjectInCollection.ToString() + " Is Examining For Removal");
                        if (_firsObjectInCollection is IModelData)
                            RecurseRemovalCallFunction(_firsObjectInCollection as IModelData);
                    }
                }
                else
                    IterateListAndRemove(list);

                UnRegisterCollectionEventHandler(list as IDomainCollection);
            }
            else
                IterateListAndRemove(list);


        }
        private void IterateListAndRemove(IList list)
        {
            foreach (object _object in list)
            {
                log.Info("data " + _object.ToString() + " Is Examining For Removal");
                if (_object is IModelData)
                    RecurseRemovalCallFunction(_object as IModelData);
            }
        }

        private void RegisterCollectionEventHandler(IDomainCollection _returnObject)
        {
            Debug.Assert(_returnObject != null);
            log.Info(_returnObject.ToString() + "registered to model ");

            _returnObject.OnChange += new EventHandler<DomainCollectionChangedEventArgs<object>>(CollectionChangedHandler);
            OnRemoveElement += new EventHandler<ModelModificationEventArgs>(_returnObject.ModelModifiedCollectionHandler);
        }
        private void UnRegisterCollectionEventHandler(IDomainCollection _returnObject)
        {
            Debug.Assert(_returnObject != null);
            log.Info(_returnObject.ToString() + "Remove registeration to model ");
            _returnObject.OnChange -= new EventHandler<DomainCollectionChangedEventArgs<object>>(CollectionChangedHandler);
            OnRemoveElement -= new EventHandler<ModelModificationEventArgs>(_returnObject.ModelModifiedCollectionHandler);
        }

        public void CollectionChangedHandler(object sender, DomainCollectionChangedEventArgs<object> Args)
        {
            if (!ListNotificationIsEnabled) return;

            System.Diagnostics.Debug.Assert(sender != null);
            if (Args.ChangeType == ChangeType.Added && Args.ChangedItem is IModelData)
                AddObject(Args.ChangedItem as IModelData);
            if (Args.ChangeType == ChangeType.Removed && Args.ChangedItem is IModelData)
                RemoveObject(Args.ChangedItem as IModelData);
            if (Args.ChangeType == ChangeType.Cleared)
            {
                foreach (object _object in Args.items)
                    RemoveObject(_object as IModelData);
            }
        }

        #endregion

        # region "XmlConfiguration for Deep Composition"

        private GeneralFunction<object> GetCopositeDataCalculationFunction(GeneralFunction<object> recurse, ActionFunction<IModelData> modificationFunction, GeneralFunction<IDomainCollection> registrationFunction)
        {
            return delegate(object _object)
            {
                if (_object == null) return;

                string _objectName = _object.GetType().Name;
                string XmlResource = ModelDataCompositionResources.GetString(_objectName);

                if (XmlResource != "" && XmlResource != null)
                {
                    XmlReader reader = XmlReader.Create(new System.IO.StringReader(XmlResource));
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Text)
                        {

                            string PropertyNameToInvoke = reader.Value;
                            if (PropertyNameToInvoke != "")
                            {
                                # region " Main Logic"

                                PropertyInfo property = _object.GetType().GetProperty(PropertyNameToInvoke);

                                MethodInfo getinfo = property.GetGetMethod(true);
                                object[] aa = new object[0];
                                object _returnObject = getinfo.Invoke(_object, aa);
                                if (_returnObject is IList)
                                {
                                    foreach (object data in (_returnObject as IList))
                                        if (data is IModelData)
                                            this.AddObject(data as IModelData);
                                    if (_returnObject is IDomainCollection)
                                        registrationFunction(_returnObject as IDomainCollection);
                                }
                                else if (_returnObject is IModelData)
                                    modificationFunction(_returnObject as IModelData);
                                else
                                    recurse(_returnObject);

                                #endregion
                            }
                        }
                    }

                }
            };
        }

        private void CheckXmlDeepAddition(object _object)
        {
            if (_object == null) return;

            string _objectName = _object.GetType().Name;
            string XmlResource = ModelDataCompositionResources.GetString(_objectName);

            if (XmlResource != "" && XmlResource != null)
            {

                XmlReader reader = XmlReader.Create(new System.IO.StringReader(XmlResource));
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Text)
                    {

                        string PropertyNameToInvoke = reader.Value;
                        if (PropertyNameToInvoke != "")
                        {
                            # region " Main Logic"

                            PropertyInfo property = _object.GetType().GetProperty(PropertyNameToInvoke);

                            MethodInfo getinfo = property.GetGetMethod(true);
                            object[] aa = new object[0];
                            object _returnObject = getinfo.Invoke(_object, aa);
                            if (_returnObject is IList)
                            {
                                foreach (object data in (_returnObject as IList))
                                    if (data is IModelData)
                                        this.AddObject(data as IModelData);
                                if (_returnObject is IDomainCollection)
                                    RegisterCollectionEventHandler(_returnObject as IDomainCollection);
                            }
                            else if (_returnObject is IModelData)
                                this.AddObject(_returnObject as IModelData);
                            else
                                CheckXmlDeepAddition(_returnObject);

                            #endregion
                        }
                    }
                }

            }

        }
        private void CheckXmlDeepRemoval(object _object)
        {
            if (_object == null) return;

            string _objectName = _object.GetType().Name;
            string XmlResource = ModelDataCompositionResources.GetString(_objectName);

            if (XmlResource != "" && XmlResource != null)
            {

                XmlReader reader = XmlReader.Create(new System.IO.StringReader(XmlResource));
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Text)
                    {

                        string PropertyNameToInvoke = reader.Value;
                        if (PropertyNameToInvoke != "")
                        {
                            # region " Main Logic"

                            PropertyInfo property = _object.GetType().GetProperty(PropertyNameToInvoke);

                            MethodInfo getinfo = property.GetGetMethod(true);
                            object[] aa = new object[0];
                            object _returnObject = getinfo.Invoke(_object, aa);
                            if (_returnObject is IList)
                            {
                                foreach (object data in (_returnObject as IList))
                                    if (data is IModelData)
                                        this.RemoveObject(data as IModelData);
                                if (_returnObject is IDomainCollection)
                                    UnRegisterCollectionEventHandler(_returnObject as IDomainCollection);
                            }
                            else if (_returnObject is IModelData)
                                this.RemoveObject(_returnObject as IModelData);
                            else
                                CheckXmlDeepRemoval(_returnObject);

                            #endregion
                        }
                    }
                }

            }

        }

        #endregion

    }

    [Serializable]
    public class ControllersFilterModelDecorator : ModelDecorator
    {
        private static readonly LoggerAdapter log = new LoggerAdapter(typeof(IModel));

        #region "Controllers implementation"
        [NonSerialized ]
        public IController AdditionController;
        [NonSerialized]
        public IController RemovalController;
        [NonSerialized]
        public Controller basecontroller;

        #endregion

        public ControllersFilterModelDecorator(IModel model,string id) : base(model) 
        {
            this.Id  = id;
            basecontroller = new Controller(model);
            basecontroller.id = "Base";
            WireUpControllers();

        }

        protected virtual void WireUpControllers()
        {
            log.Info("Models" + this.Id + "  Controllers Inisialization");

          //  Controller compositionController = new CompositionController(this);

            log.Info("Models " + this.Id + " Controllers Xml Configuration started ");
            try
            {
                XmlControllerConfigurator.Configure(this, Assembly.GetAssembly(typeof(ControllersFilterModelDecorator)), typeof(ControllersFilterModelDecorator), "XmlControllersConfigurator.xml");
            }
            catch
            {
                Trace.TraceWarning("Model_Proxy Geometry Controllers failed to  be Configured by Xml");
                log.Warn("Model_Proxy Geometry Controllers failed to  be Configured by Xml");
            }

            log.Info("Models Controllers Inisialization Finished ");


        }

        public override bool AddObject(IModelData _object)
        {
            bool validation = AdditionController.CheckAddition(_object);
            return validation;
        }

        public override bool RemoveObject(IModelData _object)
        {         
            bool validation = RemovalController.CheckRemoval (_object);
            return validation;
        }

       
    }

}
